<?php


/**
 * FTP基类.
 *
 * 定义了FTP类拥有的接口
 *
 * @author xiaoxia.xu <xiaoxia.xuxx@aliyun-inc.com>
 * @copyright ©2003-2103 phpwind.com
 * @license http://www.windframework.com
 *
 * @version $Id: AbstractWindFtp.php 3930 2013-02-05 03:55:24Z yishuo $
 */
abstract class AbstractWindFtp
{
    /**
     * ftp主机地址
     *
     * @var string
     */
    protected $server = '';

    /**
     * ftp链接端口号.
     *
     * @var int
     */
    protected $port = 21;

    /**
     * ftp链接的用户名.
     *
     * @var string
     */
    protected $user = '';

    /**
     * ftp链接的用户密码
     *
     * @var string
     */
    protected $pwd = '';

    /**
     * ftp链接之后使用的当前路径.
     *
     * @var string
     */
    protected $dir = '';

    /**
     * ftp链接的过期时间单位秒.
     *
     * @var int
     */
    protected $timeout = 10;

    /**
     * 保存ftp的跟目录路径.
     *
     * @var string
     */
    protected $rootPath = '';

    /**
     * ftp链接对象
     *
     * @var resource
     */
    protected $conn = null;

    /**
     * 初始化配置信息.
     *
     * @param array $config ftp的配置信息：
     *                      <ul>
     *                      <li>server: ftp主机地址</li>
     *                      <li>port: ftp链接端口号，默认为21</li>
     *                      <li>user: ftp链接用户名</li>
     *                      <li>pwd: ftp链接用户密码</li>
     *                      <li>dir: ftp链接后切换的目录,默认为空</li>
     *                      <li>timeout: ftp链接超时时间,默认为10秒</li>
     *                      </ul>
     *
     * @return bool 配置成功返回true,配置失败返回false
     */
    public function initConfig($config)
    {
        if (!$config || !is_array($config)) {
            return false;
        }
        isset($config['server']) && $this->server = $config['server'];
        isset($config['port']) && $this->port = $config['port'];
        isset($config['user']) && $this->user = $config['user'];
        isset($config['pwd']) && $this->pwd = $config['pwd'];
        isset($config['dir']) && $this->dir = $config['dir'];
        isset($config['timeout']) && $this->timeout = $config['timeout'];

        return true;
    }

    /**
     * 重命名文件.
     *
     * @param string $oldName 现在的文件名
     * @param string $newName 新的文件名
     *
     * @return bool 重命名成功则返回true,失败则返回false
     */
    abstract public function rename($oldName, $newName);

    /**
     * 删除文件.
     *
     * @param string $filename 待删除的文件
     *
     * @return bool 删除成功返回true,删除失败返回false
     */
    abstract public function delete($filename);

    /**
     * 上传文件.
     *
     * 'I' == BINARY mode
     * 'A' == ASCII mode
     *
     * @param string $sourceFile 待上传的文件
     * @param string $desFile    文件上传的存放位置
     * @param string $mode       上传模式二进制还是ASCII上传，I为二进制模式，A为ASCII模式，默认为A模式
     *
     * @return int 返回上传文件的大小
     */
    abstract public function upload($sourceFile, $desFile, $mode = 'I');

    /**
     * 下载文件.
     *
     * @param string $localfile  下载文件存放位置
     * @param string $remotefile 待下载的文件
     * @param string $mode       下载的模式二进制还是ASCII上传，I为二进制模式，A为ASCII模式，默认为A模式
     *
     * @return bool 返回文件下载是否成功
     */
    abstract public function download($localfile, $remotefile = '', $mode = 'I');

    /**
     * 列出给定目录的文件列表.
     *
     * @param string $dir 目录,默认为空即为当前目录
     *
     * @return array 返回该目录下的文件列表
     */
    abstract public function fileList($dir = '');

    /**
     * 关闭ftp链接.
     *
     * @return bool 返回关闭链接是否成功
     */
    abstract public function close();

    /**
     * 创建文件夹.
     *
     * @param string $dir 待创建的文件夹
     *
     * @return bool 创建文件夹成功则返回true,失败则返回false
     */
    abstract public function mkdir($dir);

    /**
     * 更改当前目录到指定目录下.
     *
     * @param string $dir 需要设置为当前目录的目录
     *
     * @return bool 设置成功则返回true,失败则返回false
     */
    abstract public function changeDir($dir);

    /**
     * 获得文件大小.
     *
     * @param string $file 待获取的文件
     *
     * @return int 获取成功返回文件大小
     */
    abstract public function size($file);

    /**
     * 获得当前路径.
     *
     * @return string 返回当前路径
     */
    abstract protected function pwd();

    /**
     * 级联创建文件夹.
     *
     * @param string $dir         待创建文件夹路径
     * @param string $permissions 创建的文件夹的权限
     *
     * @return bool 创建成功返回true创建失败返回false
     */
    public function mkdirs($dir, $permissions = 0777)
    {
        $dir = explode('/', WindSecurity::escapePath($dir));
        $dirs = '';
        $result = false;
        $count = count($dir);
        for ($i = 0; $i < $count; $i++) {
            if ('.' !== $dir[$i] && '..' !== $dir[$i]) {
                $result = $this->mkdir($dir[$i], $permissions);
                $this->changeDir($this->rootPath.$dirs.$dir[$i]);
                $dirs .= "$dir[$i]/";
            }
        }
        $this->changeDir($this->rootPath);

        return $result;
    }

    /**
     * 检查文件是否存在.
     *
     * @param string $filename 待检查的文件
     *
     * @return bool 文件存在则返回true,失败则返回false
     */
    public function file_exists($filename)
    {
        $directory = substr($filename, 0, strrpos($filename, '/'));
        $filename = str_replace("$directory/", '', $filename);
        if ($directory) {
            $directory = $this->rootPath.$directory.'/';
        } else {
            $directory = $this->rootPath;
        }
        $this->changeDir($directory);
        $list = $this->fileList();
        $this->changeDir($this->rootPath);
        if (!empty($list) && in_array($filename, $list)) {
            return true;
        }

        return false;
    }

    /**
     * 重设当前目录为初始化目录信息.
     */
    protected function initRootPath()
    {
        $this->rootPath = $this->pwd();
        if ($this->dir) {
            $this->rootPath .= trim(str_replace('\\', '/', $this->dir), '/').'/';
        }
        $this->changeDir($this->rootPath);
    }
}
